import {
  ipcMain,
  BrowserView,
  session
} from 'electron';

import { is } from '@electron-toolkit/utils'
import { ViewManager } from './client'
import { isObject, isDef, convertStrCookieToDict, getTopLevelDomain, parseProxyUrl, formatProxyInfo, getUserAgent } from './utils'
import autoUpdater from "./updater"
import { sockProxyRules } from './system/socksSessionProxy';

const views = new Map()

function isCallFunc(val){
  return isObject(val) && isDef(val.__callFunc)
}

const setupIpcHandlers = (mainWindow, app, conf) => {
  const createBrowerView = (viewID, url) => {
    const partition = `persist:${viewID}`
    const viewSession = session.fromPartition(partition)
  
    const appView = new BrowserView({
      webPreferences: {
        session: viewSession
      }
    })
  
    const view = new ViewManager(mainWindow, appView, url, viewSession)
    const viewDestroy = view.destory.bind(view)
  
    view.destory = (...destoryArgs) => {
      views.delete(viewID)
      viewDestroy(...destoryArgs)
    }
  
    return view
  }

  const createCallFunc = (callID) => {
    return (...args) => {
      mainWindow.webContents.send('callFunc', {
        callID,
        args
      })
    }
  }

  // IPC test
  ipcMain.on('ping', () => console.log('pong'))

  ipcMain.handle('createBrowerView', async (_, message) => {
    const { viewID, url, bounds, option = {} } = message

    const appView = createBrowerView(viewID, url)

    if (option.proxy){
      const ipProxyInfo = parseProxyUrl(option.proxy);
      const [playwrightProxyFormat, httpxProxyFormat] = formatProxyInfo(ipProxyInfo);
      
      const { proxyRules, destroy: destroyProxyServer } = await sockProxyRules(`socks5://${httpxProxyFormat.auth.username}:${httpxProxyFormat.auth.password}@${httpxProxyFormat.host}:${httpxProxyFormat.port}`);
      
      const viewDestroy = appView.destory.bind(appView)
  
      appView.destory = async (...destoryArgs) => {
        await destroyProxyServer()
        viewDestroy(...destoryArgs)
      }
      
      await appView.session.setProxy({ proxyRules });
    }

    appView.resize(bounds)
    appView.navigateTo(url, option.userAgent || getUserAgent(mainWindow))

    // appView.view.webContents.on('did-navigate', () => {
    //   const stealthScript = fs.readFileSync(stealth, 'utf8');
    //   appView.view.webContents.executeJavaScript(stealthScript);
    // });

    const receivedCookie = option.cookie || ''

    if(receivedCookie){
      const cookies = convertStrCookieToDict(receivedCookie)
      const topDomain = getTopLevelDomain(url)

      for(let cookieName in cookies){
        appView.session.cookies.set({
          url: url,
          name: cookieName,
          value: cookies[cookieName],
          domain: '.' + topDomain,
          path: '/',
          secure: true,
        })
      }
    }

    if (is.dev) {
      appView.view.webContents.openDevTools()
    }

    mainWindow.addBrowserView(appView.view)

    views.set(viewID, appView)
  })

  ipcMain.handle('browerViewCall', (_, message) => {
    const { viewID, method, args } = message
    const appView = views.get(viewID)

    if (typeof appView[method] === 'function') {
      return appView[method](...(args.map(arg => isCallFunc(arg) ? createCallFunc(arg.__callFunc) : arg)))
    } else {
      console.error(`browerViewCall: ${method} is not a function`)
    }
  })

  ipcMain.handle('check-updater', (_, message) => {
    autoUpdater.checkForUpdates()
  })

  ipcMain.handle('auto-updater-event', (_, message) => {
    const { event, callback } = message
    autoUpdater.on(event, createCallFunc(callback.__callFunc))
  })

  ipcMain.handle('download-update', (_, message) => {
    autoUpdater.downloadUpdate()
  })

  ipcMain.handle('quit-and-install', (_, message) => {
    app.isQuitting = true
    autoUpdater.quitAndInstall()
  })

  ipcMain.handle('set-team-id', (_, teamId) => {
    conf.set('ai_user_team', teamId)
  })
}

export default setupIpcHandlers